#include "CumulusDLL.h"


#include "Interface.h"
#include "Win32Heap.h"
#include "Win32VirtualAlloc.h"
#include "MinAlignment.h"
#include "Check.h"
#include "PrependHeader.h"
#include "FreeLists/Size.h"
#include "PerThreadFreeList.h"
#include "SharedFreeList.h"

typedef 
	Cumulus::PerThreadFreeList< Cumulus::FreeLists::Size<72, 4, 120, true>, 16,
	Cumulus::EnforceMinAlignment< 16,
	Cumulus::Win32PrivateHeap< 1024 * 1024 * 75 >
	> > TheHeapType;

TheHeapType TheHeap;

BOOL APIENTRY DllMain( HMODULE hModule,
					  DWORD  ul_reason_for_call,
					  LPVOID lpReserved
					  )
{
	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:
		break;

	case DLL_PROCESS_DETACH:
		break;

	case DLL_THREAD_ATTACH:
	case DLL_THREAD_DETACH:
		break;
	}
	return TRUE;
}


// This is an example of an exported function.
CUMULUSDLL_API void* cm_malloc( size_t Size )
{
	if( Size == 0 )
	{
		// Empty allocations are not supported. Return NULL pointer
		return NULL;
	}

	return TheHeap.Malloc( Size );
}


CUMULUSDLL_API void cm_free( void * Memory )
{
	if( Memory != NULL )
	{
		TheHeap.Free( Memory );
	}
}

CUMULUSDLL_API void* cm_realloc( void * Memory, size_t Size )
{
	if( Size == 0 )
	{
		TheHeap.Free( Memory );
		return NULL;
	}
	
	if( Memory == NULL )
	{
		return TheHeap.Malloc( Size );
	}
	
	// Try to resize in-place
	if( TheHeap.Resize( Memory, Size ) )
	{
		return Memory;
	}

	// All quick fixes failed... Allocate a new block, copy over the memory and ditch the old block.

	void* result = TheHeap.Malloc( Size );

	if( result == NULL )
	{
		return NULL; // Allocation failed
	}

	size_t originalByteCount = TheHeap.GetSize( Memory );

	if( originalByteCount < Size )
	{
		memcpy( result, Memory, originalByteCount );
	}
	else
	{
		memcpy( result, Memory, Size );
	}

	TheHeap.Free( Memory );

	return result;
}


CUMULUSDLL_API size_t cm_getusablesize( void* Memory )
{
	return TheHeap.GetSize( Memory );

}

CUMULUSDLL_API bool cm_isthreadsafe()
{
	return TheHeap.IsThreadSafe;
}
